using System;
using System.Xml;
using System.Text;
using System.Globalization;

namespace Waymex.Gps
{
	/// <summary>
	/// This object represents a single Track Log.
	/// </summary>
	/// <remarks>
    /// <para><b>Magellan Devices</b></para>
    /// <para>The following Properties are used by the Magellan devices.</para>
    /// <list type="table">
    /// <item><term>Identifier</term><description>String</description></item>
    /// <item><term>Trackpoints</term><description>Trackpoints</description></item>
    /// </list>
    /// <br/><br/>
    /// <para><b>Garmin Devices</b></para>
    /// <para>
	/// Most GPS products store only one track log (called the 'active' track log), however, some
	/// newer GPS products can store multiple track logs (in addition to the active track log). When
	/// the Host requests the GPS to send track logs, the GPS will send every Tracklog stored in its
	/// database. However only the Active Tracklog will contain Date/Time data.	
	/// </para>
	/// <para>
	/// In most cases not all of the Properties of the Tracklog object are used. The Properties
	/// actually used are determined by the protocol employed by the connected GPS Device.
	/// Below is a list of which Properties are supported by Protocol. Please note that even though a
	/// Property is identified as being supported does not mean that it will actually be used/populated.
	/// </para>
	/// <br/><br/>
	/// <para>
	/// <b>Protocol D310</b>
	/// </para>
	/// <list type="table">
	/// <listheader><term>Property</term><description>Type</description></listheader>
	/// <item><term>Display</term><description>Boolean</description></item>
	/// <item><term>Colour</term><description>Int16</description></item>
	/// <item><term>Identifier</term><description>String</description></item>
	/// <item><term>Trackpoints</term><description>Trackpoints</description></item>
	/// </list>
	/// <para>
	/// The 'Identifier' Property has a maximum length of 50 characters.
	/// </para> 
    /// <para>
    /// The Display property indicates whether the tracklog should be displayed on the map.
    /// </para>
    /// <para>
    /// The values for the 'Colour' Property are defined as follows:
    /// </para>
    /// <list type="table">
    /// <listheader><term>Value</term><description>Colour</description></listheader>
    /// <item><term>0</term><description>black</description></item>
    /// <item><term>1</term><description>dark red</description></item>
    /// <item><term>2</term><description>dark green</description></item>
    /// <item><term>3</term><description>dark yellow</description></item>
    /// <item><term>4</term><description>dark blue</description></item>
    /// <item><term>5</term><description>dark majenta</description></item>
    /// <item><term>6</term><description>dark cyan</description></item>
    /// <item><term>7</term><description>light grey</description></item>
    /// <item><term>8</term><description>dark grey</description></item>
    /// <item><term>9</term><description>red</description></item>
    /// <item><term>10</term><description>green</description></item>
    /// <item><term>11</term><description>yellow</description></item>
    /// <item><term>12</term><description>blue</description></item>
    /// <item><term>13</term><description>majenta</description></item>
    /// <item><term>14</term><description>cyan</description></item>
    /// <item><term>15</term><description>white</description></item>
    /// <item><term>255</term><description>default colour</description></item>
    /// </list>
    /// <br/><br/>
	/// <para>
	/// <b>Protocol D311</b>
	/// </para>
	/// <list type="table">
	/// <listheader><term>Property</term><description>Type</description></listheader>
	/// <item><term>Index</term><description>Int16</description></item>
	/// </list>
    /// <para>The index property is unique for all tracks received from the device.</para>
	/// <br/><br/>
	/// <para>
	/// <b>Protocol D312</b>
	/// </para>
	/// <list type="table">
	/// <listheader><term>Property</term><description>Type</description></listheader>
	/// <item><term>Display</term><description>Boolean</description></item>
	/// <item><term>Colour</term><description>Int16</description></item>
	/// <item><term>Identifier</term><description>String</description></item>
	/// <item><term>Trackpoints</term><description>Trackpoints</description></item>
	/// </list>
	/// <para>
	/// The 'Identifier' Property has a maximum length of 50 characters.
	/// </para>
    /// <para>
    /// The Display property indicates whether the tracklog should be displayed on the map.
    /// </para>
    /// <para>
    /// The Colour property can be one of the following values.
    /// <list type="table">
    /// <listheader><term>Value</term><description>Colour</description></listheader>
    /// <item><term>0</term><description>black</description></item>
    /// <item><term>1</term><description>dark red</description></item>
    /// <item><term>2</term><description>dark green</description></item>
    /// <item><term>3</term><description>dark yellow</description></item>
    /// <item><term>4</term><description>dark blue</description></item>
    /// <item><term>5</term><description>dark majenta</description></item>
    /// <item><term>6</term><description>dark cyan</description></item>
    /// <item><term>7</term><description>light grey</description></item>
    /// <item><term>8</term><description>dark grey</description></item>
    /// <item><term>9</term><description>red</description></item>
    /// <item><term>10</term><description>green</description></item>
    /// <item><term>11</term><description>yellow</description></item>
    /// <item><term>12</term><description>blue</description></item>
    /// <item><term>13</term><description>majenta</description></item>
    /// <item><term>14</term><description>cyan</description></item>
    /// <item><term>15</term><description>white</description></item>
    /// <item><term>16</term><description>transparent</description></item>
    /// <item><term>255</term><description>default colour</description></item>
    /// </list>
    /// </para>
	///</remarks>
	public class Tracklog : DataObjectBase
	{
        private short m_colour; //initialised by the run-time
        private bool m_display = true;
        private short m_index = 0;
        private string m_identifier = "";
        private TrackpointCollection m_trackPoints;

		/// <summary>
		/// See GPSLibrary Developer notes for details.
		/// </summary>
		public short Colour
        {
            get
            {
                return m_colour;
            }
            set
            {
                m_colour = value;
            }
        }

		/// <summary>
		/// See GPSLibrary Developer notes for details.
		/// </summary>
        public bool Display
        {
            get
            {
                return m_display;
            }
            set
            {
                m_display = value;
            }
        }

		/// <summary>
		/// Returns/Sets the Index property, this property.
		/// </summary>
        public short Index
        {
            get
            {
                return m_index;
            }
            set
            {
                m_index = value;
            }
        }

		/// <summary>
		/// Returns/Sets the Identifier for the Track Log. Many GPS devices do not use this property.
		/// </summary>
        public string Identifier
        {
            get
            {
                return m_identifier;
            }
            set
            {
                m_identifier = value;
            }
        }

		/// <summary>
		/// Returns a TrackPointsCollection object.
		/// </summary>
        public TrackpointCollection Trackpoints
        {
            get
            {
                return m_trackPoints;
            }
            set
            {
                m_trackPoints = value;
            }
        }

		
		private const string XML_ROOT = "gpstracklog";
		private const string XML_TRACKPOINTS = "gpstrackpoints";
		private const string XML_DISPLAY = "display";
		private const string XML_COLOUR = "colour";
		private const string XML_IDENTIFIER = "identifier";
		private const string XML_INDEX = "index";
		private const string XML_TRACKPOINT = "gpstrackpoint";

		private int m_hashCode = -1;

		/// <summary>
		/// Constructor.
		/// </summary>
		public Tracklog() : base()
		{
            Trackpoints = new TrackpointCollection();
		}

		/// <summary>
		/// Returns an XML representation of the object.
		/// </summary>
		public string ToXml()
		{
			XmlDocument objXMLDOM = new XmlDocument();

			XmlElement objRootNode = null;
			XmlElement objChildNode = null;
			string strXML = "";
			StringBuilder strbldXML = new StringBuilder("");
			
			try
			{
				//create the root node
				objRootNode = objXMLDOM.CreateElement(XML_ROOT);
			
				//append the root node to the document
				objXMLDOM.AppendChild(objRootNode);

				//create the child nodes
				AddXMLNode(objRootNode, XML_COLOUR, Colour.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_DISPLAY, Display.ToString(CultureInfo.InvariantCulture), false);
				AddXMLNode(objRootNode, XML_IDENTIFIER, Identifier, true);
				AddXMLNode(objRootNode, XML_INDEX, Index.ToString(CultureInfo.InvariantCulture), true);
				
				objChildNode = AddXMLNode(objRootNode, XML_TRACKPOINTS, "", false);
        
				//get the waypoints XML
				foreach(Trackpoint objTrackpoint in Trackpoints)
				{
					strbldXML.Append(objTrackpoint.ToXml());
				}
	
				strXML = strbldXML.ToString();

				objChildNode.InnerXml = strXML; 
				
				//append the root node of the wpt dom to our root node
				objRootNode.AppendChild(objChildNode);

				//objWptDom = null;
			
			}
            catch (NullReferenceException e)
            {
				throw new XmlException(e.Message, e);
			}

			return objXMLDOM.OuterXml;
		}

		/// <summary>
		/// This method populates the object from XML.
		/// </summary>
        public void XmlLoad(string xml)
		{
			string strXPathRoot = "";
			XmlDocument objDOM = new XmlDocument();
			XmlNode objNode = null;

			try
			{
                objDOM.LoadXml(xml);

				if(objDOM.FirstChild.Name == XML_ROOT)
				{
					strXPathRoot = string.Concat("//" , XML_ROOT , "/");

					//need to ignore type conversion errors and missing xml elements
					Colour = ReadXMLNodeAsShort(objDOM,string.Concat(strXPathRoot , XML_COLOUR));
					Display = ReadXMLNodeAsBoolean(objDOM, string.Concat(strXPathRoot, XML_DISPLAY));
					Identifier = ReadXMLNodeAsString(objDOM,string.Concat(strXPathRoot , XML_IDENTIFIER));
					Index = ReadXMLNodeAsShort(objDOM,string.Concat(strXPathRoot , XML_INDEX));
					
					try
					{
						objNode = objDOM.SelectSingleNode(string.Concat(strXPathRoot, XML_TRACKPOINTS));
						foreach(XmlNode objChildNode in objNode.ChildNodes)
						{
							switch(objChildNode.Name)
							{
								case XML_TRACKPOINT:

									Trackpoint objTrackpoint = new Trackpoint();
									objTrackpoint.XmlLoad(objChildNode.OuterXml);
									Trackpoints.Add(objTrackpoint);
									break;
							
							}

						}
					}
					catch(NullReferenceException ex)
					{
					}
				}
			}
			catch(Exception e)
			{
				throw new XmlException(e.Message ,e);
			}

		}
        /// <summary>
        /// Overridden method. Returns true of the values of each
        /// of the properties are equal in value.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>boolean</returns>
        public override bool Equals(object obj)
		{
			try
			{
				//check the type first
				if(obj.GetType() != this.GetType() )
					return false;

				//cast it
				Tracklog objTracklog = (Tracklog)obj;

				if( objTracklog.Colour != Colour ) return false; 
				if( objTracklog.Display != Display ) return false;
				if( objTracklog.Identifier != Identifier ) return false;
				if( objTracklog.Index != Index ) return false;

				if( !Trackpoints.Equals(objTracklog.Trackpoints) ) return false;

			}
			catch( NullReferenceException ex )
			{
				return false;
			}
			finally
			{
			}
			//if we get here all must be the same.
			return true;
		}
        /// <summary>
        /// Overridden function. Retrieves a value that indicates the hash code value for the object.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
		{

			//this value will be used for the overriden GetHashCode function and should
			//ensure that two object that are the same return the same Hash Code.
			//the hash code has to be imutable to is stored in a member variable.
			if( m_hashCode <= 0 )
				m_hashCode = Identifier.GetHashCode() ^ Colour.GetHashCode();

			return m_hashCode;
		}

	}
}
